
#include <QFile>
#include <QFileInfo>
#include <iostream>
#include "download_manager.h"

#define DOWNLOAD_FILE_SUFFIX "_tmp"

DownloadManager::DownloadManager(QObject *parent) : QObject(parent)
{
    network_manager_ = new QNetworkAccessManager(this);
}

DownloadManager::~DownloadManager()
{

}

void DownloadManager::downloadFile(const QString &url, const QString &fileName)
{
// 防止多次点击开始下载按钮，进行多次下载，只有在停止标志变量为true时才进行下载;
    if (is_stop_)
    {
        is_stop_ = false;
        url_ = QUrl(url);
        // 从url 中获取文件名，但不是都有效;
        // 将当前文件名设置为临时文件名，下载完成时修改回来;
        file_name_ = fileName + DOWNLOAD_FILE_SUFFIX;

        // 如果当前下载的字节数为0那么说明未下载过或者重新下载
        // 则需要检测本地是否存在之前下载的临时文件，如果有则删除
        if (bytes_current_received_ <= 0)
        {
            removeFile(file_name_);
        }

        QNetworkRequest request;
        request.setUrl(url_);

        // 如果支持断点续传，则设置请求头信息;
        if (is_support_break_point_)
        {
            QString strRange = QString("bytes=%1-").arg(bytes_current_received_);
            request.setRawHeader("Range", strRange.toLatin1());
        }

        reply_ = network_manager_->get(request);

        connect(reply_, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
        connect(reply_, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
        connect(reply_, SIGNAL(finished()), this, SLOT(onFinished()));
        connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
    }
}

void DownloadManager::setDownInto(const bool &isSupportBreakPoint)
{
    is_support_break_point_ = isSupportBreakPoint;
}

void DownloadManager::stopDownload()
{
    // 这里is_stop_变量为了保护多次点击暂停下载按钮，bytes_current_received_ 被不停累加;
    if (!is_stop_)
    {
        //记录当前已经下载字节数；
        bytes_current_received_ += bytes_received_;
        stopWork();
    }
}

void DownloadManager::closeDownload()
{
    stopWork();
    reset();
    removeFile(file_name_);
}

QString DownloadManager::getDownloadUrl()
{
    return url_.toString();
}

void DownloadManager::reset()
{
    bytes_current_received_ = 0;
    bytes_received_ = 0;
    bytes_total_ = 0;
}

void DownloadManager::stopWork()
{
    is_stop_ = true;
    if (reply_ != nullptr)
    {
        disconnect(reply_, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
        disconnect(reply_, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
        disconnect(reply_, SIGNAL(finished()), this, SLOT(onFinished()));
        disconnect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
        reply_->abort();
        reply_->deleteLater();
        reply_ = nullptr;
    }
}

void DownloadManager::removeFile(const QString &fileName)
{
    // 删除已下载的临时文件;
    QFileInfo fileInfo(fileName);
    if (fileInfo.exists())
    {
        QFile::remove(fileName);
    }
}

void DownloadManager::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    if (!is_stop_)
    {
        bytes_received_ = bytesReceived;
        bytes_total_ = bytesTotal;
        // 更新下载进度;(加上 bytes_current_received_ 是为了断点续传时之前下载的字节)
        emit signalDownloadProcess(bytes_received_ + bytes_current_received_, bytes_total_ + bytes_current_received_);
    }
}

void DownloadManager::onReadyRead()
{
    if (!is_stop_)
    {
        QFile file(file_name_);
        if (file.open(QIODevice::WriteOnly | QIODevice::Append))
        {
            file.write(reply_->readAll());
        }
        file.close();
    }
}

void DownloadManager::onFinished()
{
    is_stop_ = true;
    QVariant statusCode = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute);

    if (reply_->error() == QNetworkReply::NoError)
    {
        // 重命名临时文件;
        QFileInfo fileInfo(file_name_);
        if (fileInfo.exists())
        {
            int index = file_name_.lastIndexOf(DOWNLOAD_FILE_SUFFIX);
            QString realName = file_name_.left(index);
            QFile::rename(file_name_, realName);
        }
    }
    else
    {
        // 有错误输出错误;
        QString strError = reply_->errorString();
        std::cout << "__________" + strError.toStdString() << std::endl;
    }
    emit signalReplyFinished(statusCode.toInt());
}

void DownloadManager::onError(QNetworkReply::NetworkError code)
{
    QString strError = reply_->errorString();
    std::cout << "__________" + strError.toStdString() << std::endl;
    closeDownload();
    emit signalDownloadError();
}
